package org.example.config;


import org.springframework.data.redis.core.RedisTemplate;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * @author xietl
 * @date 2025/10/20  16:11
 * @description 分布式布隆过滤器
 */

public class RedisBloomFilter {

    private final RedisTemplate<String, Object> redisTemplate;
    private final String key;
    private static final int BIT_SIZE = 1<<24;
    //哈希函数数量
    private static final int HASH_COUNT=3;
    private static final int[] SEEDS={3,7,11};
    private final MessageDigest[] digests;
    public RedisBloomFilter(RedisTemplate<String, Object> redisTemplate, String key) {
        this.redisTemplate = redisTemplate;
        this.key = key;
        digests = new MessageDigest[HASH_COUNT];
        try{
            for(int i= 0;i<HASH_COUNT;i++){
                digests[i] = MessageDigest.getInstance("MD5");
            }
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("初始化哈希函数失败",e);
        }
    }
    /**
     * 添加元素到布隆过滤器
     * @param value 元素值
     */
    public void add(Object value){
        if(value == null) return;
        String str =value.toString();
        for(int i=0;i<HASH_COUNT;i++){
            int index = hash(str,i);
            redisTemplate.opsForValue().setBit(key,index,true);
        }
    }
    /**
     * 检查元素是否可能存在于布隆过滤器中
     * @param value 元素值
     * @return 如果元素可能存在则返回true，否则返回false
     */
    public boolean contains(Object value){
        if(value == null) return false;
        String str = value.toString();
        for(int i=0;i<HASH_COUNT;i++){
            int index = hash(str,i);
            Boolean inset = redisTemplate.opsForValue().getBit(key,index);
            if(inset == null || !inset) return false;
        }
        return true;
    }
    /**
     * 哈希函数
     * @param str 元素字符串表示
     * @param seedIndex 哈希种子索引
     * @return 哈希值
     */
    private int hash(String str,int seedIndex){
        try {
            byte[] bytes = digests[seedIndex].digest(str.getBytes());
            int hash = 0;
            for(byte b : bytes){
                hash = hash * 31+(b & 0xFF);
            }
            return Math.abs(hash)%BIT_SIZE;
        } catch (Exception e) {
            throw new RuntimeException("哈希函数计算失败",e);
        }
    }
}
